package com.song.codesandbox.utils;

import cn.hutool.core.util.ArrayUtil;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.PullImageCmd;
import com.github.dockerjava.api.command.PullImageResultCallback;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DockerClientConfig;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

/**
 * Docker工具类
 */
@Slf4j
public class DockerUtils {


    // region docker客户端配置与创建

    /**
     * 获取自定义Docker客户端配置
     * todo 可以增加更多参数不同的函数，提供更加灵活的配置
     *
     * @return Docker客户端配置
     */
    public static DockerClientConfig getDockerClientConfig(String dockerHost, String apiVersion) {
        return new DefaultDockerClientConfig.Builder().withDockerTlsVerify(false)
                // 这里填最上面填的ip端口号，ip换成服务器ip
                .withDockerHost("tcp://81.70.164.218:2375")
                // docker API版本号，可以用docker version查看
                .withApiVersion("1.43").build();
    }

    /**
     * 获取默认的Docker客户端
     *
     * @return Docker客户端配置
     */
    public static DockerClient getDefaultDockerClient() {
        return DockerClientBuilder.getInstance().build();
    }

    /**
     * 获取自定义配置的Docker客户端
     *
     * @param dockerClientConfig Docker客户端配置
     * @return Docker客户端
     */
    public static DockerClient getDockerClient(DockerClientConfig dockerClientConfig) {
        return DockerClientBuilder.getInstance(dockerClientConfig).build();
    }

    // endregion

    // region docker镜像工具

    /**
     * 下载镜像
     *
     * @param dockerClient Docker客户端
     * @param imageName    镜像名称
     * @throws InterruptedException
     */
    public static void pullImage(DockerClient dockerClient, String imageName) throws InterruptedException {
        PullImageCmd pullImageCmd = dockerClient.pullImageCmd(imageName);
        log.info("开始下载{}镜像", imageName);
        pullImageCmd.exec(new PullImageResultCallback() {
            @Override
            public void onNext(PullResponseItem item) {
                log.info("镜像下载状态: {}", item.getStatus());
                super.onNext(item);
            }
        }).awaitCompletion();
        log.info("{}镜像下载完成", imageName);
    }

    /**
     * 判断镜像是否存在
     *
     * @param dockerClient Docker客户端
     * @param imageName    镜像名称
     * @return 如果镜像存在返回true, 否则返回false
     */
    public static boolean hasContainer(DockerClient dockerClient, String imageName) {
        return dockerClient.listContainersCmd().exec().stream().anyMatch(container -> container.getImage().equals(imageName));
    }

    // endregion


    // region docker容器操作

    /**
     * 创建容器
     *
     * @param dockerClient Docker客户端
     * @param imageName    镜像名称
     * @param codePath     编译后的代码路径
     * @return containerId 新创建的容器id
     */
    public static String createContainer(DockerClient dockerClient, String imageName, String codePath) {
        CreateContainerCmd containerCmd = dockerClient.createContainerCmd(imageName);
        HostConfig hostConfig = new HostConfig();
        // 设置最大内存
//        hostConfig.withMemory(100 * 1000 * 1000L);
//        hostConfig.withMemorySwap(0L);
        // todo linux安全配置
//        hostConfig.withSecurityOpts(Arrays.asList(""));
//        hostConfig.withCpuCount(1L);
        hostConfig.setBinds(new Bind(codePath, new Volume("/app")));
        CreateContainerResponse containerResponse = containerCmd.withHostConfig(hostConfig)
                // 禁用网络
                .withNetworkDisabled(true)
                // 禁止用户向根目录写文件
//                .withReadonlyRootfs(true)
                .withAttachStdin(true).withAttachStderr(true).withAttachStdout(true).withTty(true).exec();
        return containerResponse.getId();
    }

    // todo 创建容器可以给出更多的配置，更多不同参数的方法，以及设置一些默认参数，比如内存大小，cpu数量等


    /**
     * 获取主机配置，在此是获取容器配置特定选项
     * 这些选项通常与容器运行的主机环境相关
     * 1. 资源限制：可以设置容器可以使用的最大内存、CPU份额等资源限制。
     * 2. 端口绑定：允许你指定容器的端口如何映射到宿主机的端口上。
     * 3. 网络配置：可以设置容器的网络模式，例如桥接模式（bridge），或者使用已存在的网络。
     * 4. 存储配置：包括绑定挂载（bind mounts）、卷（volumes）和 tmpfs。
     * 5. 设备访问：允许容器访问宿主机的特定设备。
     * 6. 配置内核参数：例如，可以配置内核的sysctls参数。
     * 7. 运行时特权：例如，可以设置容器是否有特权运行。
     * 8. 重启策略：设置容器的重启条件。
     * @param bind
     * @return
     */
    public static HostConfig getHostConfig(Bind bind) {
        HostConfig hostConfig = new HostConfig();
        hostConfig.withMemory(100 * 1000 * 1000L);
        hostConfig.withCpuCount(1L);
        hostConfig.withMemorySwap(0L);
        hostConfig.setBinds(bind);

        return hostConfig;
    }
    // endregion
}
